package com.sita.bike.utils;

import android.app.ProgressDialog;
import android.os.Environment;

import com.google.gson.reflect.TypeToken;
import com.sita.bike.persistence.Route;
import com.sita.bike.persistence.RouteData;
import com.sita.bike.rest.RestClient;
import com.sita.bike.rest.model.RestResponse;
import com.sita.bike.rest.model.UploadRouteResponseData;
import com.sita.bike.rest.model.UploadRouteHeaderParams;
import com.sita.bike.rest.model.response.SyncTrackHeader;
import com.sita.bike.rest.model.response.SyncTrackItem;
import com.sita.bike.rest.model.response.SyncTrackListResponse;
import com.sita.bike.rest.model.response.SyncTrackRTData;
import com.sita.bike.rest.model.response.SyncTrackRTDataSection;
import com.sita.bike.support.Constants;
import com.sita.tboard.util.ZipUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import retrofit.Callback;
import retrofit.RetrofitError;
import retrofit.client.Response;
import retrofit.mime.TypedFile;
import retrofit.mime.TypedString;

/**
 * Created by lijuan zhang on 2016/3/2.
 */
public class TracksInfoUtils {

    private final static String TAG = TracksInfoUtils.class.getSimpleName();

    public static String getTracksDistance(List<Route> tracks) {
        long totalTracksDistance = 0;
        Iterator<Route> iterator = tracks.iterator();
        while (iterator.hasNext()) {
            Route track = iterator.next();
            if (track.getDistance() != null)
                totalTracksDistance = totalTracksDistance + track.getDistance();
        }
        return formatDistance(totalTracksDistance);
    }

    public static String getTracksTime(List<Route> tracks) {
        long totalTracksTime = 0;
        Iterator<Route> iterator = tracks.iterator();
        while (iterator.hasNext()) {
            Route track = iterator.next();
            long startTime = track.getStartTime();
            long endTime = startTime;
            if (track.getEndTime() != null) {
                endTime = track.getEndTime();
            } else {
                //取这条路线的最后一个点的时间
                List<RouteData> gpsLocationList = PersistUtils.getRouteDataList(track.getId());
                if (gpsLocationList.size() != 0) {
                    RouteData routeData = gpsLocationList.get(gpsLocationList.size() - 1);
                    endTime = routeData.getTime();
                }
            }
            long timeInterval = endTime - startTime;//相差多少微秒
            if (timeInterval > 0)
                totalTracksTime = totalTracksTime + timeInterval;
        }
        return formatTime(totalTracksTime);
    }

    private static String formatDistance(float distance) {
        float distanceKm = distance / 1000;
        String distanceResult = "0";
        DecimalFormat decimalFormat;
        if (distanceKm < 10) {
            decimalFormat = new DecimalFormat("0.00");
            distanceResult = decimalFormat.format(distanceKm);
        } else if (distance >= 10 && distance < 100) {
            decimalFormat = new DecimalFormat("0.0");
            distanceResult = decimalFormat.format(distanceKm);
        } else if (distance >= 100) {
            decimalFormat = new DecimalFormat("0");
            distanceResult = decimalFormat.format(distanceKm);
        }
        return distanceResult;
    }

    private static String formatTime(long time) {
        long hour, min, s;
        String hourShow, minShow = null;
        String timeResult = "0:0";
        if ((time / 1000) < 60) {//小于一分钟

        } else if ((time / 1000) >= 60 && (time / 1000) < 3600) {//大于一分钟，小于一小时
            min = time / (1000 * 60);
//            s = time / 1000 - min * 60;
            if (min < 10) {
                minShow = "0" + min;
            } else {
                minShow = String.valueOf(min);
            }
            timeResult = "00:" + minShow;
        } else if ((time / 1000) >= 3600) {
            hour = time / (60 * 60 * 1000);
            min = (time / (60 * 1000)) - hour * 60;
            if (hour < 10) {
                hourShow = "0" + hour;
            } else {
                hourShow = String.valueOf(hour);
            }
            if (min < 10) {
                minShow = "0" + min;
            } else {
                minShow = String.valueOf(min);
            }
            timeResult = hourShow + ":" + minShow;
        }
        return timeResult;
    }

    /*******************
     * Upload track
     *******************************/
    public interface UploadTrackListener {
        public void Success(long routeId);

        public void Fail();
    }

    public static void uploadTrack(ProgressDialog dialog, final UploadTrackListener listener, final long mTrackId) {


        new Thread(new Runnable() {
            @Override
            public void run() {


                //构造json，压缩上传数据
                List<RouteData> routeRTDataList = PersistUtils.getRouteDataList(mTrackId);
                FileOutputStream fileOutputStream = null;
                File originalFile = new File(Environment.getExternalStorageDirectory(), mTrackId + ".json");
                try {

                    fileOutputStream = new FileOutputStream(originalFile);
                    if (!originalFile.exists()) {
                        originalFile.createNewFile();
                    } else {
                        originalFile.delete();
                        originalFile.createNewFile();
                    }

                    SyncTrackRTDataSection section = new SyncTrackRTDataSection();
                    section.mPoints = new ArrayList<>();
                    for (RouteData rd : routeRTDataList) {
                        SyncTrackRTData data = new SyncTrackRTData();
                        data.mTime = rd.getTime();
                        data.mLatitude = rd.getLatitude();
                        data.mLongitude = rd.getLongitude();
                        data.mSpeed = rd.getSpeed() == null ? 0 : rd.getSpeed();
                        data.mShift = rd.getShift() == null ? 0 : rd.getShift();
                        data.mRpm = rd.getRpm() == null ? 0 : rd.getRpm();
                        section.mPoints.add(data);
                    }
                    String jsonStr = RestClient.getGson().toJson(section);
                    LogUtils.i(TAG, "Json Str >>>>>" + jsonStr);
                    FileWriter file = new FileWriter(originalFile);
                    try {
                        file.write(jsonStr);
                    } catch (IOException e) {
                        LogUtils.i(TAG, "write into json file error");
                        e.printStackTrace();
                    } finally {
                        file.flush();
                        file.close();
                    }
//                    fileOutputStream.write(jsonStr.getBytes());
//                    fileOutputStream.flush();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        if (fileOutputStream != null) {
                            fileOutputStream.close();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                File zipFile = new File(Environment.getExternalStorageDirectory(), mTrackId + ".zip");
                try {
                    if (!zipFile.exists()) {
                        zipFile.createNewFile();
                    } else {
                        zipFile.delete();
                        zipFile.createNewFile();
                    }
                    ZipUtils.zipFile(originalFile, zipFile);
                    //上传，监听成功后，删除两个文件
                } catch (IOException e) {
                    e.printStackTrace();
                }

                TypedFile uploadFile = (zipFile.equals("")) ? null : new TypedFile("zip", zipFile);
                UploadRouteHeaderParams uploadRouteHeaderParams = new UploadRouteHeaderParams();
                final Route route = PersistUtils.getRoute(mTrackId);
                uploadRouteHeaderParams.mMileage = route.getDistance();
                uploadRouteHeaderParams.mMaxSpeed = route.getMaxSpeed();
                uploadRouteHeaderParams.mMaxRpm = route.getMaxRpm();
                String[] latlong = route.getStartLoc().split(",");
                uploadRouteHeaderParams.mStartLat = Double.valueOf(latlong[0]);
                uploadRouteHeaderParams.mStartLong = Double.valueOf(latlong[1]);
                latlong = route.getEndLoc().split(",");
                uploadRouteHeaderParams.mEndLat = Double.valueOf(latlong[0]);
                uploadRouteHeaderParams.mEndLong = Double.valueOf(latlong[1]);
                uploadRouteHeaderParams.mStartTime = route.getStartTime() == null ? 0 : route.getStartTime();
                uploadRouteHeaderParams.mEndTime = route.getEndTime() == null ? 0 : route.getEndTime();
                TypedString uploadParams = new TypedString(RestClient.getGson().toJson(uploadRouteHeaderParams));
                RestClient.getRestService().uploadRoadTrust(AccountUtils.getAccountID(), uploadParams, uploadFile, new Callback<RestResponse>() {
                    @Override
                    public void success(RestResponse restResponse, Response response) {
                        if (restResponse.mErrorCode.equals("0")) {
//                            if (originalFile.isFile() && originalFile.exists()) {
//                                originalFile.delete();
//                            }
//                            if (zipFile.isFile() && zipFile.exists()) {
//                                zipFile.delete();
//                            }
                            String s = RestClient.getGson().toJson(restResponse.mData);
                            UploadRouteResponseData uploadRouteResponseData = RestClient.getGson().fromJson(s, UploadRouteResponseData.class);
                            long routeId = uploadRouteResponseData.mRouteId;
                            route.setServerRouteId(String.valueOf(routeId));
                            route.setSyncStatus(Constants.ROUTE_FILE_SYNC_STATUS_UPLOADED);
                            PersistUtils.updateRoute(route);
                            listener.Success(routeId);
                        } else {
                            listener.Fail();
                        }
                    }

                    @Override
                    public void failure(RetrofitError error) {
                        PersistUtils.updateRoute(route);
                        listener.Fail();
                    }
                });
            }
        }).start();
    }

    /*******************
     * Sync tracks
     *******************************/
    public interface SyncListener {
        public void Success(boolean hasSynced);

        public void Fail();
    }

    private static int mTrackCount = 0;

    public static synchronized void increaseCount() {
        mTrackCount++;
    }

    public static synchronized void decreaseCount() {
        mTrackCount--;
    }

    public static synchronized int getTrackCount() {
        return mTrackCount;
    }

    public static void syncTracks(final SyncListener listener) {

        new Thread(new Runnable() {
            @Override
            public void run() {

                // 0.1 fetch all not uploaded tracks
                List<Route> routes = PersistUtils.getRoutesNotUploaded();
                for (final Route route : routes) {
                    uploadTrack(null, new UploadTrackListener() {
                        @Override
                        public void Success(long routeId) {
                            LogUtils.i(TAG, "uploaded missed track id : " + route.getId());
                        }

                        @Override
                        public void Fail() {

                        }
                    }, route.getId());
                }

                // 1. fetch the track list
                String accountId = AccountUtils.getAccountID();

                RestClient.getRestNormalService().syncTracksList(accountId, new Callback<SyncTrackListResponse>() {
                    @Override
                    public void success(SyncTrackListResponse syncTrackListResponse, Response response) {
                        // 2. compare with the local data
                        boolean isNeedSync = false;
                        List<SyncTrackItem> tracks = syncTrackListResponse.mTrackList;

                        for (SyncTrackItem track : tracks
                                ) {
                            String trackId = track.mTrackId;
                            Route localTrack = PersistUtils.getRouteByServerId(trackId);
                            if (localTrack != null && hasSyncedWithServer(localTrack)) {
                                LogUtils.i(TAG, "x by pass sync id: " + localTrack.getServerRouteId());
                                continue;
                            } else {
                                isNeedSync = true;
                                // save the track info
                                increaseCount();

                                if (localTrack == null) {

                                    SyncTrackHeader trackHeader = RestClient.getGson().fromJson(track.mHeader, SyncTrackHeader.class);
                                    localTrack = new Route();
                                    localTrack.setDescription(trackHeader.description);
                                    localTrack.setDistance(trackHeader.mileage);
                                    localTrack.setStartTime(trackHeader.startTime);
                                    localTrack.setEndTime(trackHeader.endTime);
                                    localTrack.setServerRouteId(track.mTrackId);
                                    localTrack.setFilePath(track.mTrackFile);
                                    localTrack.setMaxRpm(trackHeader.maxRpm);
                                    localTrack.setMaxSpeed(trackHeader.maxSpeed);
                                    localTrack.setStartLoc(String.valueOf(trackHeader.startLat) + "," + String.valueOf(trackHeader.startLong));
                                    localTrack.setEndLoc(String.valueOf(trackHeader.endLat) + "," + String.valueOf(trackHeader.endLong));
                                    localTrack.setSyncStatus(Constants.ROUTE_FILE_SYNC_STATUS_DOWNLOAD_NOT);

                                    PersistUtils.saveRoute(localTrack);
                                }

                                LogUtils.i(TAG, "v need to sync id: " + localTrack.getServerRouteId());
                            }

                            // 3. download file
                            String fileUrl = track.mTrackFile;

                            new FileUtils.DownloadFileAsync().execute(fileUrl, localTrack.getId().toString());


                        }

                        LogUtils.w("track sync", "ok");
                        listener.Success(isNeedSync);

                    }

                    @Override
                    public void failure(RetrofitError error) {

                    }
                });
            }
        }).start();


    }

    public static boolean hasSyncedWithServer(Route route) {
        // sync ok, will delete the filepath in table
        return !route.getSyncStatus().equals(Constants.ROUTE_FILE_SYNC_STATUS_DOWNLOAD_NOT);
    }

    public static void setTrackSynced(String trackId) {
        Route localTrack = PersistUtils.getRoute(Long.valueOf(trackId));
        localTrack.setSyncStatus(Constants.ROUTE_FILE_SYNC_STATUS_DOWNLOADED);
        PersistUtils.saveRoute(localTrack);
    }

    public static void readTrackIntoLocalDB(String trackId, String datafile) {
        long startTime = System.currentTimeMillis();
        // read file and put it into db;
        // Find the directory for the SD Card using the API
        // *Don't* hardcode "/sdcard"
        File sdcard = Environment.getExternalStorageDirectory();

        // Get the text file
        File file = new File(datafile);

        // Read text from file
        StringBuilder text = new StringBuilder();

        try {
            BufferedReader br = new BufferedReader(new FileReader(file));
            String line;

            while ((line = br.readLine()) != null) {
                text.append(line);
            }
            text.append('\n');
            br.close();
        } catch (IOException e) {
            //You'll need to add proper error handling here
        }


//        List<SyncTrackRTData> datas = RestClient.getGson().fromJson(text.toString(),
//                new TypeToken<List<SyncTrackRTData>>() {
//                }.getType());
        SyncTrackRTDataSection section = RestClient.getGson().fromJson(text.toString(), SyncTrackRTDataSection.class);

        for (SyncTrackRTData rtdata : section.mPoints
                ) {
            RouteData routeData = new RouteData();
            routeData.setLatitude(rtdata.mLatitude);
            routeData.setLongitude(rtdata.mLongitude);
            routeData.setSpeed(rtdata.mSpeed);
            routeData.setTime(rtdata.mTime);
            routeData.setRpm(rtdata.mRpm);
            routeData.setRouteId(Integer.valueOf(trackId));
            PersistUtils.saveRouteData(routeData);
        }

        LogUtils.d("SaveDate", "cost time:" + String.valueOf(System.currentTimeMillis() - startTime));
    }
}
